package com.haohan.jingyuan.user.service;

import com.haohan.jingyuan.common.constants.CacheConstants;
import com.haohan.jingyuan.common.enums.ErrorEnum;
import com.haohan.jingyuan.common.exception.BusinessException;
import com.haohan.jingyuan.gateway.holder.UserContextHolder;
import com.haohan.jingyuan.user.dao.AdminInfoMapper;
import com.haohan.jingyuan.user.dto.req.LoginRequest;
import com.haohan.jingyuan.user.dto.resp.LoginResp;
import com.haohan.jingyuan.user.entity.AdminInfo;
import com.haohan.jingyuan.util.CacheUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.UUID;

/**
 * 管理员服务实现：提供管理员认证相关业务逻辑。
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class AdminService {

    private final AdminInfoMapper adminInfoMapper;
    private final CacheUtil cacheUtil;

    /**
     * 登录
     * <p>
     *
     * @param loginRequest 请求参数
     * @return 认证成功时返回JWT token（格式：userName uuid），认证失败时返回null
     * @throws BusinessException 当登录次数超过限制时抛出业务异常
     */
    public LoginResp login(LoginRequest loginRequest) {
        String username = loginRequest.getUsername();
        String password = loginRequest.getPassword();
        if (StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
            log.warn("管理员登录用户名和密码不可为空");
            return null;
        }

        // 登录次数校验：每日5次
        String cacheKey = CacheConstants.CACHE_LOGIN_TIMES_ + username;
        Integer loginTimes = cacheUtil.get(cacheKey, Integer.class);
        if (loginTimes == null) {
            loginTimes = 0;
        } else if (loginTimes > 5) {
            throw new BusinessException(ErrorEnum.LOGIN_TIMES);
        }

        // 对入参密码进行 MD5 摘要后再比对
        String md5Password = DigestUtils.md5Hex(password);
        AdminInfo adminInfo = adminInfoMapper.findByUsernameAndPassword(username, md5Password);

        if (adminInfo == null) {
            cacheUtil.put(cacheKey, loginTimes++);
            return null;
        }

        // 登录成功，生成token并缓存
        LoginResp loginResp = new LoginResp();
        loginResp.setAuthToken(generateAndCacheToken(adminInfo));
        loginResp.setUserId(adminInfo.getUserId());
        loginResp.setUserName(adminInfo.getUserName());
        // 登录成功，token缓存用户信息
        cacheUtil.put(loginResp.getAuthToken(), adminInfo);

        return loginResp;
    }

    /**
     * 管理员登出
     * <p>
     * 删除登录时生成的token，使token失效
     *
     * @return 登出是否成功
     */
    public boolean logout() {
        String userId = UserContextHolder.getCurrentUserId();
        String authToken = UserContextHolder.getCurrentToken();

        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(authToken)) {
            log.warn("非法操作：登出异常，用户id或authToken为空,userId={},authToken={}", userId, authToken);
            throw new BusinessException(ErrorEnum.LOGOUT_ERROR);
        }

        try {
            AdminInfo adminInfo = cacheUtil.get(authToken, AdminInfo.class);
            if (adminInfo != null) {
                if (!adminInfo.getUserId().equals(userId)) {
                    log.warn("非法操作：登录时用户id与authToken不符合,userId={},authToken={}", userId, authToken);
                    throw new BusinessException(ErrorEnum.LOGOUT_ERROR);
                }
                cacheUtil.remove(authToken);
                return true;
            } else {
                return false;
            }
        } catch (Exception e) {
            log.error("管理员登出失败，userId={},authToken={}", userId, authToken, e.getMessage(), e);
            return false;
        }
    }

    /**
     * 修改用户密码
     * <p>
     * 将新密码进行MD5加密后更新到数据库
     *
     * @param userId      用户ID
     * @param newPassword 新密码（明文）
     * @param modifier    修改人
     * @return 更新是否成功
     */
    public boolean updatePassword(String userId, String newPassword, String modifier) {
        if (StringUtils.isEmpty(userId) || StringUtils.isEmpty(newPassword) || StringUtils.isEmpty(modifier)) {
            log.warn("修改密码失败：用户ID、新密码或修改人不能为空，userId={}, modifier={}", userId, modifier);
            return false;
        }

        try {
            // 对新密码进行MD5加密
            String md5Password = DigestUtils.md5Hex(newPassword);

            // 更新密码
            int updateCount = adminInfoMapper.updatePasswordByUserId(userId, md5Password, modifier);

            if (updateCount > 0) {
                log.info("修改密码成功，userId={}, modifier={}", userId, modifier);
                return true;
            } else {
                log.warn("修改密码失败：用户不存在或更新失败，userId={}, modifier={}", userId, modifier);
                return false;
            }
        } catch (Exception e) {
            log.error("修改密码异常，userId={}, modifier={}", userId, modifier, e);
            return false;
        }
    }

    /**
     * 生成并缓存管理员登录token。
     *
     * @param adminInfo 管理员信息
     * @return 生成的token（格式：userName uuid）
     */
    private String generateAndCacheToken(AdminInfo adminInfo) {
        String uuid = UUID.randomUUID().toString().replace("-", "");
        return adminInfo.getUserId() + " " + uuid;
    }
}